/*
As3 Performances Analyzer
Copyright (C) 2011 Ankama Studio

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Contact : seyraud@ankama.com
Project : http://code.google.com/p/as3-performances-analyzer
*/

package ui.components
{
	import flash.display.LineScaleMode;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.DropShadowFilter;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.utils.Dictionary;
	
	import mx.flash.UIMovieClip;
	
	import spark.core.SpriteVisualElement;
	
	import types.GraphSerie;
	import types.SubProvider;
	
	public class GraphPoint extends SpriteVisualElement
	{
		private static var _colors : Dictionary = new Dictionary;
		private var _serie : GraphSerie;
		private var __height : Number;
		private var _renderShape : Shape;
		private var _overCursor : Sprite;
		private var _overCursorText : TextField;
		private var _legendData : Array;
		private var __width : Number;
		
		// Line style
		private var _lineSize : Number = 1.0;
		private var _lineColor : uint = 0x000000;
		private var _lineAlpha : Number = 1;
		private var _legend : String;
		
		public static var DISPLAY_TOOLTIPS : Boolean = true;
		public static var DISPLAY_NEAREST_TOOLTIPS : Boolean = true;
		
		public override function set height(value:Number):void
		{
			__height = value;
			render();
		}
		
		public override function get height():Number
		{
			return __height;
		}
		
		public override function get width():Number
		{
			return __width;
		}
		
		public function setLineStyle(size : Number, color : uint, alpha : Number) : void
		{
			_lineSize = size;
			_lineColor = color;
			_lineAlpha = alpha;
			
			_overCursor.graphics.clear();
			_overCursor.graphics.lineStyle(3,color, 1.0, false, LineScaleMode.NONE);
			_overCursor.graphics.beginFill(0xffffff);
			_overCursor.graphics.drawCircle(0,0,4);
			_overCursor.graphics.endFill();
			
			render();
		}
		
		public function GraphPoint(s : GraphSerie)
		{
			super();
			_serie = s;
			_serie.addEventListener(Event.CHANGE, onChange);
			_renderShape = new Shape;
			_overCursor = new Sprite;
			_overCursor.visible = false;
			_overCursorText = new TextField;
			_overCursorText.selectable = false;
			_overCursorText.height = 20;
			_overCursorText.border = true;
			_overCursorText.borderColor = 0xeeeeee;
			_overCursorText.background = true;
			_overCursorText.backgroundColor = 0xfefefe;
			_overCursorText.y = -30;
			var tf  : TextFormat = new TextFormat;
			tf.align = TextFormatAlign.CENTER;
			tf.font = "verdana";
			_overCursorText.defaultTextFormat = tf;
			_overCursorText.filters = [new DropShadowFilter(1,45,0,.5,5,5)];
			_overCursor.addChild(_overCursorText);
			addChild(_renderShape);
			addChild(_overCursor);
			setLineStyle(1, _serie.color, 1);
			addEventListener(Event.ADDED_TO_STAGE, onDisplayed);
			
			if(s.provider.data.length)
				__width = s.provider.data[s.provider.data.length - 1].timestamp;
		}

		private function onChange(event:Event):void
		{
			setLineStyle(1, _serie.color, 1);
			render();
			visible = _serie.visible;
		}
		
		private function render() : void
		{
			_renderShape.graphics.clear();
			if(_serie && _serie.provider.data.length)
			{
				__width = _serie.provider.data[_serie.provider.data.length - 1].timestamp;
				_legendData = [];
				_renderShape.scaleY = -1;
				_renderShape.y = __height;
				_renderShape.graphics.lineStyle(_lineSize, _lineColor, _lineAlpha, false, LineScaleMode.NONE);
				var first : Boolean = true;
				var dataProvider : SubProvider = _serie.provider;
				var lastX : uint = uint.MAX_VALUE;
				for(var i : uint = 0; i < dataProvider.data.length; ++i)
				{
					var data : * = dataProvider.data[i];
					var value : String = dataProvider.data[i][_serie.dataField];
					if(!_colors[value])
					{
						var j : uint;
						var r : uint;
						var g : uint;
						var b : uint;
						while(data.name && j++ < data.name.length)
						{
							switch(j % 3)
							{
								case 0:
									r += data.name.charCodeAt(j) % 256; break;
								case 1:
									g += data.name.charCodeAt(j) % 256; break;
								case 2:
									b += data.name.charCodeAt(j) % 256; break;
							}
						}
						r = 0xAA - r % 50;
						g = 0xAA - g % 50;
						b = 0xAA - b % 50;
						_colors[value] = ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
					}
					
					var x : Number = data[dataProvider.abscissField] * dataProvider.abscissScale;
					if(x != lastX)
					{
						var y : Number = height / 2;
						_legendData.push({x:x, y:y, value:dataProvider.legend ? dataProvider.legend.split("#").join(value) : value});
						_renderShape.graphics.lineStyle(1, _colors[value], 1, false, LineScaleMode.NONE);
						_renderShape.graphics.moveTo(x, 0);
						_renderShape.graphics.lineTo(x, y);
						lastX = x;
					}
				}
			}
		}
		
		private function onDisplayed(e:Event) : void
		{
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}	
		
		private var _lastX : int;
		private var _lastY : int;
		private function onEnterFrame(e:Event) : void
		{
			if(!visible) return;
			if(!DISPLAY_TOOLTIPS)
			{
				_overCursor.visible = false;
				return;
			}
			var mX : int = _renderShape.mouseX;
			var mY : int = _renderShape.mouseY;
			if(_lastX != mX || _lastY != mY)
			{
				_lastX = mX;
				_lastY = mY;
				var dist : Number = 99999;
				var tmpDist : Number;
				var data : Object;
				var lastData : Object;
				for each(data in _legendData)
				{
					tmpDist = Math.abs(data.x - mX);
					if(tmpDist < dist)
					{
						lastData = data;
						dist = tmpDist;
					}
				}
				data = lastData;
				if(data && DISPLAY_NEAREST_TOOLTIPS && Math.abs(Math.sqrt(Math.pow(data.x - mouseX, 2) + Math.pow(__height - data.y - mouseY, 2))) > 200)
					data = null;
				if(!data)
					_overCursor.visible = false;
				else
				{
					_overCursor.scaleX = 1/parent.parent.scaleX;
					_overCursor.visible = true;
					_overCursor.x = data.x;
					_overCursor.y = __height - data.y;
					_overCursorText.text = data.value+ "";
					_overCursorText.width = _overCursorText.textWidth + 5;
					_overCursorText.x = -_overCursorText.width / 2;
				}
			}
		}
	}
}